<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>WebRTC Offer/Answer 调试</title>
    <script src="https://cdnjs.cloudflare.com/ajax/libs/microsoft-signalr/6.0.1/signalr.min.js"></script>
    <style>
        body { font-family: Arial, sans-serif; padding: 20px; }
        .log { background: #f8f9fa; padding: 15px; margin: 10px 0; height: 400px; overflow-y: auto; border: 1px solid #dee2e6; border-radius: 5px; }
        .debug { background: #e3f2fd; color: #0d47a1; }
        .success { background: #e8f5e8; color: #2e7d32; }
        .error { background: #ffebee; color: #c62828; }
        .warning { background: #fff3e0; color: #f57c00; }
        button { margin: 5px; padding: 10px 15px; cursor: pointer; }
        input { margin: 5px; padding: 8px; width: 200px; }
        .grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; }
        .section { border: 1px solid #ccc; padding: 15px; border-radius: 5px; }
    </style>
</head>
<body>
    <h1>WebRTC Offer/Answer 调试工具</h1>
    
    <div class="grid">
        <div class="section">
            <h3>用户 A (发起方)</h3>
            <input type="text" id="userNameA" placeholder="用户名A" value="UserA">
            <button onclick="joinUserA()">加入系统</button>
            <button onclick="createRoomA()">创建房间</button>
            <button onclick="startVideoA()">开启摄像头</button>
            <button onclick="startCallA()">发起通话</button>
            <div>状态: <span id="statusA">未连接</span></div>
            <div>用户ID: <span id="userIdA">-</span></div>
            <div>房间ID: <span id="roomIdA">-</span></div>
        </div>
        
        <div class="section">
            <h3>用户 B (接收方)</h3>
            <input type="text" id="userNameB" placeholder="用户名B" value="UserB">
            <button onclick="joinUserB()">加入系统</button>
            <button onclick="joinRoomB()">加入房间</button>
            <button onclick="startVideoB()">开启摄像头</button>
            <button onclick="acceptCallB()">接听通话</button>
            <div>状态: <span id="statusB">未连接</span></div>
            <div>用户ID: <span id="userIdB">-</span></div>
            <div>房间ID: <span id="roomIdB">-</span></div>
        </div>
    </div>
    
    <div>
        <h3>视频区域</h3>
        <video id="localVideoA" width="300" height="200" autoplay muted playsinline style="border: 2px solid red; margin: 5px;"></video>
        <video id="localVideoB" width="300" height="200" autoplay muted playsinline style="border: 2px solid blue; margin: 5px;"></video>
        <video id="remoteVideoA" width="300" height="200" autoplay playsinline style="border: 2px dotted red; margin: 5px;"></video>
        <video id="remoteVideoB" width="300" height="200" autoplay playsinline style="border: 2px dotted blue; margin: 5px;"></video>
    </div>
    
    <div>
        <h3>调试日志</h3>
        <button onclick="clearLog()">清空日志</button>
        <button onclick="exportLog()">导出日志</button>
        <div id="debugLog" class="log"></div>
    </div>

    <script>
        // 全局变量
        let connectionA = null, connectionB = null;
        let userIdA = null, userIdB = null;
        let roomIdA = null, roomIdB = null;
        let localStreamA = null, localStreamB = null;
        let peerConnectionA = null, peerConnectionB = null;
        let pendingOfferB = null;

        // WebRTC配置
        const iceServers = {
            iceServers: [
                { urls: 'stun:stun.l.google.com:19302' },
                { urls: 'stun:stun1.l.google.com:19302' }
            ]
        };

        // 日志函数
        function log(message, type = 'info', user = '') {
            const logDiv = document.getElementById('debugLog');
            const timestamp = new Date().toLocaleTimeString();
            const colors = {
                'success': '#28a745',
                'error': '#dc3545', 
                'warning': '#ffc107',
                'info': '#17a2b8',
                'debug': '#6c757d'
            };
            
            const logEntry = document.createElement('div');
            logEntry.style.color = colors[type] || '#000';
            logEntry.style.marginBottom = '5px';
            logEntry.innerHTML = `[${timestamp}] ${user ? `[${user}] ` : ''}${message}`;
            
            logDiv.appendChild(logEntry);
            logDiv.scrollTop = logDiv.scrollHeight;
            
            console.log(`[${user || 'DEBUG'}] ${message}`);
        }

        function clearLog() {
            document.getElementById('debugLog').innerHTML = '';
        }

        function exportLog() {
            const logContent = document.getElementById('debugLog').innerText;
            const blob = new Blob([logContent], { type: 'text/plain' });
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = `webrtc-debug-${new Date().toISOString()}.txt`;
            a.click();
            URL.revokeObjectURL(url);
        }

        // 初始化连接A
        async function initConnectionA() {
            connectionA = new signalR.HubConnectionBuilder()
                .withUrl("https://localhost:5001/signaling")
                .withAutomaticReconnect()
                .configureLogging(signalR.LogLevel.Debug)
                .build();

            connectionA.on("UserJoined", (data) => {
                log(`UserJoined 事件: ${JSON.stringify(data)}`, 'debug', 'A');
                const userId = data.userId || data.UserId;
                if (!userIdA && userId) {
                    userIdA = userId;
                    document.getElementById('userIdA').textContent = userId;
                    document.getElementById('statusA').textContent = '已加入系统';
                }
            });

            connectionA.on("RoomCreated", (data) => {
                const roomId = data.roomId || data.RoomId;
                roomIdA = roomId;
                document.getElementById('roomIdA').textContent = roomId;
                log(`房间创建成功: ${roomId}`, 'success', 'A');
            });

            connectionA.on("ReceiveAnswer", async (data) => {
                log(`收到 Answer: ${JSON.stringify(data)}`, 'debug', 'A');
                try {
                    if (peerConnectionA && data.Answer) {
                        log(`Answer 数据检查: type=${data.Answer.type}, sdp存在=${!!data.Answer.sdp}`, 'debug', 'A');
                        await peerConnectionA.setRemoteDescription(new RTCSessionDescription(data.Answer));
                        log(`Answer 设置成功`, 'success', 'A');
                    }
                } catch (error) {
                    log(`处理 Answer 失败: ${error}`, 'error', 'A');
                }
            });

            connectionA.on("Error", (message) => {
                log(`服务器错误: ${message}`, 'error', 'A');
            });

            await connectionA.start();
            log('SignalR 连接成功', 'success', 'A');
        }

        // 初始化连接B
        async function initConnectionB() {
            connectionB = new signalR.HubConnectionBuilder()
                .withUrl("https://localhost:5001/signaling")
                .withAutomaticReconnect()
                .configureLogging(signalR.LogLevel.Debug)
                .build();

            connectionB.on("UserJoined", (data) => {
                log(`UserJoined 事件: ${JSON.stringify(data)}`, 'debug', 'B');
                const userId = data.userId || data.UserId;
                if (!userIdB && userId) {
                    userIdB = userId;
                    document.getElementById('userIdB').textContent = userId;
                    document.getElementById('statusB').textContent = '已加入系统';
                }
            });

            connectionB.on("JoinedRoom", (data) => {
                const roomId = data.roomId || data.RoomId;
                roomIdB = roomId;
                document.getElementById('roomIdB').textContent = roomId;
                log(`加入房间成功: ${roomId}`, 'success', 'B');
            });

            connectionB.on("ReceiveOffer", async (data) => {
                log(`收到 Offer: ${JSON.stringify(data)}`, 'debug', 'B');
                log(`Offer 数据详细检查:`, 'debug', 'B');
                log(`  - data.Offer 存在: ${!!data.Offer}`, 'debug', 'B');
                if (data.Offer) {
                    log(`  - data.Offer 类型: ${typeof data.Offer}`, 'debug', 'B');
                    log(`  - data.Offer.type: ${data.Offer.type}`, 'debug', 'B');
                    log(`  - data.Offer.sdp 存在: ${!!data.Offer.sdp}`, 'debug', 'B');
                    log(`  - data.Offer 完整内容: ${JSON.stringify(data.Offer)}`, 'debug', 'B');
                }
                pendingOfferB = data;
            });

            connectionB.on("Error", (message) => {
                log(`服务器错误: ${message}`, 'error', 'B');
            });

            await connectionB.start();
            log('SignalR 连接成功', 'success', 'B');
        }

        // 用户A操作
        async function joinUserA() {
            const userName = document.getElementById('userNameA').value;
            await connectionA.invoke("JoinUser", userName);
            log(`用户A加入: ${userName}`, 'info', 'A');
        }

        async function createRoomA() {
            await connectionA.invoke("CreateRoom", "TestRoom", 10);
            log('创建房间', 'info', 'A');
        }

        async function startVideoA() {
            try {
                localStreamA = await navigator.mediaDevices.getUserMedia({
                    video: true,
                    audio: true
                });
                document.getElementById('localVideoA').srcObject = localStreamA;
                log('摄像头A开启成功', 'success', 'A');
            } catch (error) {
                log(`摄像头A开启失败: ${error}`, 'error', 'A');
            }
        }

        async function startCallA() {
            try {
                if (!userIdB) {
                    log('用户B未准备好', 'warning', 'A');
                    return;
                }

                log(`开始创建 PeerConnection A`, 'info', 'A');
                peerConnectionA = new RTCPeerConnection(iceServers);
                
                // 添加本地流
                if (localStreamA) {
                    localStreamA.getTracks().forEach(track => {
                        peerConnectionA.addTrack(track, localStreamA);
                    });
                }

                // 处理远程流
                peerConnectionA.ontrack = (event) => {
                    document.getElementById('remoteVideoA').srcObject = event.streams[0];
                    log('接收到远程流A', 'success', 'A');
                };

                // 创建 Offer
                const offer = await peerConnectionA.createOffer({
                    offerToReceiveAudio: true,
                    offerToReceiveVideo: true
                });

                log(`Offer 已创建:`, 'debug', 'A');
                log(`  - offer.type: ${offer.type}`, 'debug', 'A');
                log(`  - offer.sdp 存在: ${!!offer.sdp}`, 'debug', 'A');

                await peerConnectionA.setLocalDescription(offer);
                log('本地描述设置成功', 'success', 'A');

                // 发送 Offer
                await connectionA.invoke("SendOffer", userIdB, offer);
                log(`Offer 已发送给用户B: ${userIdB}`, 'success', 'A');

            } catch (error) {
                log(`发起通话失败: ${error}`, 'error', 'A');
            }
        }

        // 用户B操作
        async function joinUserB() {
            const userName = document.getElementById('userNameB').value;
            await connectionB.invoke("JoinUser", userName);
            log(`用户B加入: ${userName}`, 'info', 'B');
        }

        async function joinRoomB() {
            if (!roomIdA) {
                log('房间A未创建', 'warning', 'B');
                return;
            }
            await connectionB.invoke("JoinRoom", roomIdA);
            log(`加入房间: ${roomIdA}`, 'info', 'B');
        }

        async function startVideoB() {
            try {
                localStreamB = await navigator.mediaDevices.getUserMedia({
                    video: true,
                    audio: true
                });
                document.getElementById('localVideoB').srcObject = localStreamB;
                log('摄像头B开启成功', 'success', 'B');
            } catch (error) {
                log(`摄像头B开启失败: ${error}`, 'error', 'B');
            }
        }

        async function acceptCallB() {
            try {
                if (!pendingOfferB) {
                    log('没有待处理的 Offer', 'warning', 'B');
                    return;
                }

                const data = pendingOfferB;
                log(`开始处理 Offer 从用户: ${data.FromName}`, 'info', 'B');

                // 详细的 Offer 数据检查
                log(`Offer 数据最终验证:`, 'debug', 'B');
                if (data.Offer) {
                    log(`  - typeof data.Offer: ${typeof data.Offer}`, 'debug', 'B');
                    log(`  - data.Offer.type: ${data.Offer.type}`, 'debug', 'B');
                    log(`  - data.Offer.sdp 长度: ${data.Offer.sdp ? data.Offer.sdp.length : 'N/A'}`, 'debug', 'B');
                    
                    // 检查是否为null或undefined
                    log(`  - data.Offer.type === null: ${data.Offer.type === null}`, 'debug', 'B');
                    log(`  - data.Offer.type === undefined: ${data.Offer.type === undefined}`, 'debug', 'B');
                    log(`  - data.Offer.type 长度: ${data.Offer.type ? data.Offer.type.length : 'N/A'}`, 'debug', 'B');
                } else {
                    log(`  - data.Offer 为空或不存在`, 'error', 'B');
                    return;
                }

                // 创建 PeerConnection B
                peerConnectionB = new RTCPeerConnection(iceServers);
                
                // 添加本地流
                if (localStreamB) {
                    localStreamB.getTracks().forEach(track => {
                        peerConnectionB.addTrack(track, localStreamB);
                    });
                }

                // 处理远程流
                peerConnectionB.ontrack = (event) => {
                    document.getElementById('remoteVideoB').srcObject = event.streams[0];
                    log('接收到远程流B', 'success', 'B');
                };

                // 设置远程描述
                log('准备设置远程描述...', 'debug', 'B');
                await peerConnectionB.setRemoteDescription(new RTCSessionDescription(data.Offer));
                log('远程描述设置成功', 'success', 'B');

                // 创建 Answer
                const answer = await peerConnectionB.createAnswer();
                log(`Answer 已创建: type=${answer.type}, sdp存在=${!!answer.sdp}`, 'debug', 'B');

                await peerConnectionB.setLocalDescription(answer);

                // 发送 Answer
                await connectionB.invoke("SendAnswer", data.From, answer);
                log(`Answer 已发送给用户A: ${data.From}`, 'success', 'B');

                pendingOfferB = null;

            } catch (error) {
                log(`接受通话失败: ${error}`, 'error', 'B');
                log(`错误详情: ${error.message}`, 'error', 'B');
                log(`错误堆栈: ${error.stack}`, 'debug', 'B');
            }
        }

        // 页面加载时初始化
        window.addEventListener('load', async () => {
            try {
                await initConnectionA();
                await initConnectionB();
                log('调试页面初始化完成', 'success');
            } catch (error) {
                log(`初始化失败: ${error}`, 'error');
            }
        });
    </script>
</body>
</html> 